package com.simple.business.service.sms;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.simple.business.domain.constant.SimpleConstant;
import com.simple.business.domain.dto.sms.WeixinMPQRCodeDTO;
import com.simple.business.domain.dto.sms.WeixinMPUserBaseInfoDTO;
import com.simple.business.domain.properties.WeixinMPProperties;
import com.simple.business.service.utilService.DictionaryService;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Slf4j
@Service
public class WeixinMPService implements AuthRequest {
    private static final String ACCESS_TOKEN_REDIS_KEY = "weixinmp_access_token";
    private static final String WEI_XIN_MP_QR_LOGIN_REDIS_KEY = "weixinmp_qr_login:";

    private static RestTemplate restTemplate = new RestTemplate();
    @Resource
    private WeixinMPProperties weixinMPProperties;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private DictionaryService dictionaryService;

    private String getAccessToken(){
        Object obj = redisTemplate.opsForValue().get(ACCESS_TOKEN_REDIS_KEY);
        if(obj != null){
            return obj.toString();
        }
        Map<String,String> requestMap = new HashMap<>();
        requestMap.put("grant_type","client_credential");
        requestMap.put("appid",weixinMPProperties.getAppid());
        requestMap.put("secret",weixinMPProperties.getSecret());

        try {
            String resultStr = restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/stable_token", requestMap, String.class);
            JSONObject result = JSON.parseObject(resultStr);
            String accessToken = result.getString("access_token");
            Integer expiresIn = result.getInteger("expires_in");
            redisTemplate.opsForValue().set(ACCESS_TOKEN_REDIS_KEY,accessToken, Duration.ofSeconds(expiresIn));
            return accessToken;
        }catch (Exception exception){
            log.error("获取微信公众号AccessToken异常",exception);
        }
        return null;
    }

    public WeixinMPQRCodeDTO createQRCode(String sceneStr, Integer expireSeconds){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("expire_seconds",expireSeconds);
        jsonObject.put("action_name","QR_STR_SCENE");
        jsonObject.putObject("action_info").putObject("scene").put("scene_str",sceneStr);
        String accessToken = getAccessToken();
        if(accessToken == null){
            return null;
        }
        try {
            WeixinMPQRCodeDTO weixinMPQRCodeDTO = restTemplate.postForObject("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+accessToken, jsonObject, WeixinMPQRCodeDTO.class);
            return weixinMPQRCodeDTO;
        }catch (Exception exception){
            log.error("微信公众号生成带参数的二维码异常",exception);
        }
        return null;
    }

    public Boolean createMenu(String json) {
        String accessToken = getAccessToken();
        if (accessToken == null) {
            return null;
        }
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;
            String result = restTemplate.postForObject(url, JSONObject.parseObject(json), String.class);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject.getInteger("errcode").equals(0)) {
                return true;
            }
            log.error("微信公众号创建菜单失败:{}", result);
            return false;
        } catch (Exception exception) {
            log.error("微信公众号创建菜单异常", exception);
        }
        return null;
    }

    public WeixinMPUserBaseInfoDTO getUserInfoByOpenid(String openid){
        String accessToken = getAccessToken();
        if(accessToken == null){
            return null;
        }
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken+"&openid="+openid+"&lang=zh_CN";
            WeixinMPUserBaseInfoDTO forObject = restTemplate.getForObject(url, WeixinMPUserBaseInfoDTO.class);
            if(forObject.getErrcode() != null || StringUtils.isNotBlank(forObject.getErrmsg())){
                log.error("微信公众号获取用户基本信息失败:{}",forObject);
                return null;
            }
            return forObject;
        }catch (Exception exception){
            log.error("微信公众号获取用户基本信息异常",exception);
        }
        return null;
    }
    private String getReplyContent(String openid,String mpid,String content){
        return "<xml>\n" +
                "  <ToUserName><![CDATA["+openid+"]]></ToUserName>\n" +
                "  <FromUserName><![CDATA["+mpid+"]]></FromUserName>\n" +
                "  <CreateTime>"+(System.currentTimeMillis() / 1000)+"</CreateTime>\n" +
                content+
                "</xml>";
    }
    public String weixinMPCallbackHandle(Map<String, String> map) {
        log.info("收到微信回调消息：{}",map);
        String event = map.get("Event");
        String eventKey = map.get("EventKey");
        String userName = map.get("FromUserName");
        String ourName = map.get("ToUserName");
        String msgType = map.get("MsgType");
        if("event".equals(msgType)){
            switch (event){
                case "subscribe":
                    //订阅
                    log.info("用户:{}订阅了公众号",userName);
                    if(StringUtils.isNotBlank(eventKey)){
                        // 扫码登录
                        eventKey = eventKey.replace("qrscene_","");
                        setOpenidToCode(eventKey,userName);
                    }
                    String dictionaryValue = dictionaryService.getDictionaryValue(SimpleConstant.WEI_XIN_MP_GROUP, SimpleConstant.WEI_XIN_MP_AUTO_REPLY_key);
                    if(StringUtils.isNotBlank(dictionaryValue)){
                        return getReplyContent(userName,ourName,dictionaryValue);
                    }
                    break;
                case "unsubscribe":
                    //取消订阅
                    log.info("用户:{}取消订阅了",userName);
                    break;
                case "SCAN":
                    //扫码已关注
                    if(StringUtils.isNotBlank(eventKey)){
                        setOpenidToCode(eventKey,userName);
                    }
                    break;
                case "CLICK":
                    //点击菜单
                    if(StringUtils.isNotBlank(eventKey)){
                        String content = dictionaryService.getDictionaryValue(SimpleConstant.WEI_XIN_MP_GROUP, eventKey);
                        if(StringUtils.isNotBlank(content)){
                            return getReplyContent(userName,ourName,content);
                        }
                    }
                    break;
                case "VIEW":
                    //点击菜单跳转链接
                    break;
            }
        }else if("text".equals(msgType)){
            return getReplyContent(userName,ourName,"<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[感谢您的留言]]></Content>");
        }

        return "";
    }

    @Override
    public AuthResponse login(AuthCallback authCallback) {
        String openid = authCallback.getCode();
        WeixinMPUserBaseInfoDTO userInfoByOpenid = getUserInfoByOpenid(openid);
        if (userInfoByOpenid != null){
            String unionid = userInfoByOpenid.getUnionid();
            AuthUser user = AuthUser.builder()
                    .rawUserInfo(null)
                    .nickname("公众号用户"+ RandomStringUtils.randomAlphabetic(6))
                    .uuid(StringUtils.isBlank(unionid)?userInfoByOpenid.getOpenid():unionid)
                    .source(null)
                    .build();
            return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(user).build();
        }
        return AuthResponse.builder().code(AuthResponseStatus.FAILURE.getCode()).msg("请重新扫码重试").build();
    }

    public WeixinMPQRCodeDTO createLoginQRCode(){
        String randomId = UUID.randomUUID().toString().replace("-", "");
        String key = WEI_XIN_MP_QR_LOGIN_REDIS_KEY + randomId;
        WeixinMPQRCodeDTO qrCode = createQRCode(randomId, 300);
        if (qrCode != null) {
            redisTemplate.opsForValue().set(key, "", Duration.ofSeconds(300));
            qrCode.setCode(randomId);
            return qrCode;
        }
        return null;
    }

    public String getOpenidByCode(String code) {
        String key = WEI_XIN_MP_QR_LOGIN_REDIS_KEY + code;
        Object o = redisTemplate.opsForValue().get(key);
        if (o == null) {
            return null;
        }
        String openid = o.toString();
        if (StringUtils.isNotBlank(openid)) {
            redisTemplate.delete(key);
        }
        return openid;
    }

    public void setOpenidToCode(String code, String openid) {
        String key = WEI_XIN_MP_QR_LOGIN_REDIS_KEY + code;
        redisTemplate.opsForValue().set(key, openid, Duration.ofSeconds(300));
    }

}
